//
//  AVPlayerManager.m
//  PlayerSample
//
//  Created by lingqineng on 2017/9/6.
//  Copyright © 2017年 lingqineng. All rights reserved.
//

#import "AVPlayerManager.h"
#import "MJExtension.h"
#import "TYMemo.h"
#import <lame/lame.h>


@interface AVPlayerManager ()
@property (nonatomic,assign) CMTime duration;
@end

@implementation AVPlayerManager
- (instancetype)init{
    self = [super init];
    if (self) {
        self.isPlaying = NO;
        [self backPlay];
    }
    return self;
}

+(AVPlayerManager *)manager{
    static AVPlayerManager * manager = nil;
    static dispatch_once_t predicte;
    dispatch_once (&predicte,^{
        manager = [[AVPlayerManager alloc] init];
    });
    return manager;
}

- (void)backPlay {
    // 获取音频会话
    AVAudioSession *session = [AVAudioSession sharedInstance];
    // 设置会话类别为后台播放
    NSError *error;
    if (![session setCategory:AVAudioSessionCategoryPlayback error:&error]) {
        NSLog(@"Category Error: %@",[error localizedDescription]);
    }
    // 激活会话
    [session setActive:YES error:nil];
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}

- (void)resetAudio{
    [self.player pause];
    [self.currentMusicItem seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
        
    }];
//    [self.player replaceCurrentItemWithPlayerItem:self.currentMusicItem];
    self.isPlaying = NO;
//    self.player = nil;
}

- (void)setAVPlayerURL:(NSURL*)url{
    self.currentMusicItem = [AVPlayerItem playerItemWithURL:url];
    if (self.player) {
        [self.player replaceCurrentItemWithPlayerItem:self.currentMusicItem];
    } else {
        self.player = [AVPlayer playerWithPlayerItem:self.currentMusicItem];
    }
    [self addProgressObserver];

}

- (void)play{
    if ([AVAudioSession sharedInstance].category != AVAudioSessionCategoryPlayback) {
        [self backPlay];
    }
    
    if (!self.isPlaying) {
        [self.player play];
    }
    
    self.isPlaying = YES;
}

- (void)pause{
    if (self.isPlaying) {
        [self.player pause];
    }
    
    self.isPlaying = NO;
}

- (void)previous{
    self.currentIndex --;
}

- (void)next{
    self.currentIndex ++;
}

- (void)seekToTimeInterval:(double)currentTime{
    [self.player seekToTime:CMTimeMakeWithSeconds(currentTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}

#pragma mark ------------------------------------ setter method -------------------------------------
- (void)setCurrentIndex:(NSInteger)currentIndex{
    _currentIndex = currentIndex;
}

/**
 *  根据playerItem，来添加移除观察者
 *
 *  @param currentMusicItem playerItem
 */
-(void)setCurrentMusicItem:(AVPlayerItem *)currentMusicItem{
    if (_currentMusicItem == currentMusicItem) {
        return;
    }
    if (_currentMusicItem) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_currentMusicItem];
        [_currentMusicItem removeObserver:self forKeyPath:@"status"];
    }
    _currentMusicItem = currentMusicItem;
    if (currentMusicItem) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(trackPlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:currentMusicItem];
        [currentMusicItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    }
}

-(void)trackPlayDidEnd:(NSNotification *)notification{
    [self.player seekToTime:CMTimeMakeWithSeconds(0, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
    self.isPlaying = NO;
    if ([self.delegate respondsToSelector:@selector(trackPlayDidEnd)]) {
        NSLog(@"发送代理");
        [self.delegate trackPlayDidEnd];
    }
}

#pragma mark - 监听
- (void)addProgressObserver {
    __weak typeof(self) weakSelf = self;
    [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 20.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        
//        CGFloat allTime = CMTimeGetSeconds(weakSelf.duration);
//        CGFloat currentTime = CMTimeGetSeconds(weakSelf.player.currentItem.currentTime);
        double allTime = CMTimeGetSeconds(weakSelf.player.currentItem.duration);

        CGFloat currentTime = CMTimeGetSeconds(time);
        weakSelf.allTime = allTime;
        weakSelf.currentTime = currentTime;
//        if (weakSelf.centUpdatTime) {
//            weakSelf.progressSlider.value = currentTimeF / allTimeF;
//            weakSelf.progressView2.progress = currentTimeF / allTimeF;
//        }
        
//        double allTime = CMTimeGetSeconds(weakSelf.player.currentItem.duration);
//        double currentTime = CMTimeGetSeconds(weakSelf.player.currentItem.currentTime);
        if (currentTime <=0) {
            currentTime = 0;
        }

        //        int allHour = allTime / (60*60);
        int allMin  = (int)allTime / 60;
        int allSecond  = (int)allTime % 60;
        int allMillisecond  = (allTime - allSecond)*100;


        //        int currentHour = currentTime / (60*60);
        int currentMin  = (int)currentTime / 60;
        int currentSecond  = (int)currentTime % 60;
        int millisecond = (currentTime - currentSecond)*100 - currentMin*60*100;

        NSString *aullTime = [NSString stringWithFormat:@"%.2d:%.2d.%02d",allMin,allSecond, allMillisecond];
        NSString *currentTime1 = [NSString stringWithFormat:@"%.2d:%.2d.%02d",currentMin,currentSecond, millisecond];
        CGFloat scale = currentTime/allTime;
        NSLog(@"总时长：%f 当前时间%f 播放进度比例：%f 播放状态：%ld 播放时间：%@/%@",allTime,currentTime, scale,weakSelf.isPlaying,currentTime1,aullTime);
        if ([weakSelf.delegate respondsToSelector:@selector(timeRunAndTime:andValue:andScale:)]) {
            [weakSelf.delegate timeRunAndTime:currentTime andValue:currentTime1 andScale:scale];
        }
    }];
}

#pragma mark getter method
-(AVPlayer *)player{
    if (!_player) {
        _player = [[AVPlayer alloc]init];
    }
    return _player;
}


#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItem *item = (AVPlayerItem *)object;
        AVPlayerItemStatus status = [change[@"new"] integerValue];
        switch (status) {
            case AVPlayerItemStatusReadyToPlay:
            {
                NSLog(@"准备播放");
                _duration = item.duration;
            }
                break;
            case AVPlayerItemStatusFailed:
            {
                NSLog(@"加载失败");
                self.isPlaying = NO;
                [[UIViewControllerCJHelper findCurrentShowingViewController] showHUDAlert:@"音频错误"];
            }
                break;
            case AVPlayerItemStatusUnknown:
            {
                NSLog(@"未知资源");
                self.isPlaying = NO;
            }
                break;
            default:
                self.isPlaying = NO;
                break;
        }
    }
}

+ (NSString *)getTmpRecordName:(NSString *)name{
    NSString *tmpDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"recording"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:tmpDir]){
        [fileManager createDirectoryAtPath:tmpDir withIntermediateDirectories:YES attributes:nil error:nil];
    }
    NSString *filePath = [tmpDir stringByAppendingPathComponent:name];
    return filePath;
}
//裁剪音频
+ (void)cutAudioStartTime:(CGFloat)source endTime:(CGFloat)end withPath:(NSString *)path completed:(void (^)(NSString *successPath))completed {
    NSString *recordName = dateTurnTimeNameStr([NSDate date]);
    NSString *m4aOutPath = [self getTmpRecordName:[NSString stringWithFormat:@"%@.m4a", recordName]];
//    NSString *wavOutPath = [self getTmpRecordName:[NSString stringWithFormat:@"%@.wav", recordName]];
    //音频输出会话
    AVURLAsset *videoAsset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:path]];
    //音频输出会话
    //AVAssetExportPresetAppleM4A:(输出音频,并且是.m4a格式)
    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:videoAsset presetName:AVAssetExportPresetAppleM4A];
    exportSession.outputURL = [NSURL fileURLWithPath:m4aOutPath];
    exportSession.outputFileType = AVFileTypeAppleM4A;
    exportSession.timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(source, 600), CMTimeMakeWithSeconds(end, 600));
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        //exporeSession.status
        if (AVAssetExportSessionStatusCompleted == exportSession.status) {
            completed(m4aOutPath);
//            [self convertM4aToWav:m4aOutPath outPath:wavOutPath success:^(id parameter) {
//                completed(parameter);
//            }];
        } else if (AVAssetExportSessionStatusFailed == exportSession.status) {
            NSLog(@"剪切失败！");
        }else{
             NSLog(@"Export Session Status: %ld", (long)exportSession.status);
        }
    }];
}
//拆分音频
+ (void)splitAudioTime:(CGFloat)source withPath:(NSString *)path completed:(void (^)(NSString *path1, NSString *path2))completed {
    NSString *recordName = dateTurnTimeNameStr([NSDate date]);
    NSString *m4aOutPath1 = [self getTmpRecordName:[NSString stringWithFormat:@"%@-1.m4a", recordName]];
    NSString *m4aOutPath2 = [self getTmpRecordName:[NSString stringWithFormat:@"%@-2.m4a", recordName]];

    //音频输出会话
    AVURLAsset *videoAsset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:path]];
    CGFloat start1 = 0;
    CGFloat end1 = source;
    CGFloat start2 = source;
    CGFloat end2 = CMTimeGetSeconds(videoAsset.duration);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    //音频输出会话1
    AVAssetExportSession *exportSession1 = [AVAssetExportSession exportSessionWithAsset:videoAsset presetName:AVAssetExportPresetAppleM4A];
    exportSession1.outputURL = [NSURL fileURLWithPath:m4aOutPath1];
    exportSession1.outputFileType = AVFileTypeAppleM4A;
    exportSession1.timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(start1, 600), CMTimeMakeWithSeconds(end1, 600));
    [exportSession1 exportAsynchronouslyWithCompletionHandler:^{
        //exporeSession.status
        if (AVAssetExportSessionStatusCompleted == exportSession1.status) {
//            completed(m4aOutPath1);
        } else if (AVAssetExportSessionStatusFailed == exportSession1.status) {
            NSLog(@"剪切失败！");
        }else{
             NSLog(@"Export Session Status: %ld", (long)exportSession1.status);
        }
        dispatch_group_leave(group);
    }];
    dispatch_group_enter(group);
    //音频输出会话2
    AVAssetExportSession *exportSession2 = [AVAssetExportSession exportSessionWithAsset:videoAsset presetName:AVAssetExportPresetAppleM4A];
    exportSession2.outputURL = [NSURL fileURLWithPath:m4aOutPath2];
    exportSession2.outputFileType = AVFileTypeAppleM4A;
    exportSession2.timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(start2, 600), CMTimeMakeWithSeconds(end2, 600));
    [exportSession2 exportAsynchronouslyWithCompletionHandler:^{
        //exporeSession.status
        if (AVAssetExportSessionStatusCompleted == exportSession2.status) {
//            completed(m4aOutPath);
        } else if (AVAssetExportSessionStatusFailed == exportSession2.status) {
            NSLog(@"剪切失败！");
        }else{
             NSLog(@"Export Session Status: %ld", (long)exportSession2.status);
        }
        dispatch_group_leave(group);
    }];
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        completed(m4aOutPath1, m4aOutPath2);
    });
}
//合并音频
+ (void)mergeAudios:(NSArray *)paths destnation:(NSString *)outputPath completed:(void (^)(NSString *successPath))completed {
    if (paths.count == 0 || outputPath == nil) {
        return;
    }
    AVMutableComposition *composition = [AVMutableComposition composition];
    // 设置音频合并音轨
    AVMutableCompositionTrack *compositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    // 开始时间
    CMTime beginTime = kCMTimeZero;
    NSError *error = nil;
    for (NSString *path in paths) {
        NSURL *url;
        if ([path isKindOfClass:[NSURL class]]) {
            url = (NSURL *)path;
        }else{
            url = [NSURL fileURLWithPath:path];
        }
        // 音频文件资源
        AVURLAsset *asset = [AVURLAsset assetWithURL:url];
        // 需要合并的音频文件的区间
        CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
        // ofTrack 音频文件内容
        AVAssetTrack *track = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;
        //
        [compositionTrack insertTimeRange:timeRange ofTrack:track atTime:beginTime error:&error];
        if (error) {
            NSLog(@"error:%@",error);
        }
        beginTime = CMTimeAdd(beginTime, asset.duration);
    }
    [[NSFileManager defaultManager] removeItemAtPath:outputPath error:nil];
    // 导出合并的音频
    // presetName 与 outputFileType 要对应
    AVAssetExportSession *export = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
    export.outputURL = [NSURL fileURLWithPath:outputPath];
    export.outputFileType = AVFileTypeAppleM4A;
    export.shouldOptimizeForNetworkUse = YES;
    [export exportAsynchronouslyWithCompletionHandler:^{
        if (AVAssetExportSessionStatusCompleted == export.status) {
            completed(outputPath);
//            [self convertM4aToWav:m4aOutPath outPath:wavOutPath success:^(id parameter) {
//                completed(parameter);
//            }];
        } else if (AVAssetExportSessionStatusFailed == export.status) {
            NSLog(@"合并失败！");
        }else{
             NSLog(@"Export Session Status: %ld", (long)export.status);
        }
    }];
}

+(void) convertAudio:(NSURL*)url outputURL:(NSURL*)outputURL completed:(void (^)(NSString *successPath))completed
{
    
}

//转m4a格式
+ (void)convertToM4a:(NSString *)originalPath outPath:(NSString *)outPath success:(void (^)(NSString *successPath))completed{
    NSURL* srcUrl = [NSURL fileURLWithPath:originalPath];
    AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:srcUrl options:nil];
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:audioAsset presetName:AVAssetExportPresetAppleM4A];
    session.outputURL = [NSURL fileURLWithPath:outPath];
    session.outputFileType = AVFileTypeAppleM4A;
    [session exportAsynchronouslyWithCompletionHandler:^{
        if (AVAssetExportSessionStatusCompleted == session.status) {
            completed(outPath);
        } else if (AVAssetExportSessionStatusFailed == session.status) {
            NSLog(@"转换失败！");
        }else{
             NSLog(@"Export Session Status: %ld", (long)session.status);
        }
    }];
}

//m4a格式转wav格式
+ (void)convertM4aToWav:(NSString *)originalPath outPath:(NSString *)outPath success:(void (^)(NSString *successPath))completed{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:outPath]) {
        [fileManager removeItemAtPath:outPath error:nil];
    }
    NSURL *originalUrl = [NSURL fileURLWithPath:originalPath];
    NSURL *outPutUrl = [NSURL fileURLWithPath:outPath];
    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:originalUrl options:nil];    //读取原始文件信息
    NSError *error = nil;
    AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset error:&error];
    if (error) {
        NSLog (@"error: %@", error);
        return;
    }
    AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks audioSettings: nil];
    if (![assetReader canAddOutput:assetReaderOutput]) {
        NSLog (@"can't add reader output... die!");
        return;
    }
    [assetReader addOutput:assetReaderOutput];
    
    AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:outPutUrl                                                            fileType:AVFileTypeCoreAudioFormat error:&error];
    if (error) {
        NSLog (@"error: %@", error);
        return;
    }
    AudioChannelLayout channelLayout;
    memset(&channelLayout, 0, sizeof(AudioChannelLayout));
    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
    
    /** 配置音频参数 */
    NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                    [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                    [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                    [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
                                    [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                    [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
                                    nil];
    AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio                                                                                outputSettings:outputSettings];
    if ([assetWriter canAddInput:assetWriterInput]) {
        [assetWriter addInput:assetWriterInput];
    } else {
        NSLog (@"can't add asset writer input... die!");
        return;
    }
    assetWriterInput.expectsMediaDataInRealTime = NO;
    [assetWriter startWriting];
    [assetReader startReading];
    AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
    CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
    [assetWriter startSessionAtSourceTime:startTime];
    __block UInt64 convertedByteCount = 0;
    dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
    [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue  usingBlock: ^      {
        while (assetWriterInput.readyForMoreMediaData) {
            CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
            if (nextBuffer) {
                // append buffer
                [assetWriterInput appendSampleBuffer: nextBuffer];
                convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
            } else {
                [assetWriterInput markAsFinished];
                [assetWriter finishWritingWithCompletionHandler:^{
                }];
                [assetReader cancelReading];
                
                NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]                                                        attributesOfItemAtPath:[outPutUrl path]                                                        error:nil];
                NSLog (@"FlyElephant %lld",[outputFileAttributes fileSize]);
                completed(outPath);
                break;
            }
        }
    }];
}

//转换为mp3
+ (void)convenrtToMp3WithResult:(NSString *)originalPath outPath:(NSString *)outPath completed:(void (^)(NSString *successPath))completed{
    [[NSFileManager defaultManager] removeItemAtPath:outPath error:nil];
    @try {
        int read, write;
        FILE *pcm = fopen([originalPath cStringUsingEncoding:1], "rb");//被转换的文件
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([outPath cStringUsingEncoding:1], "wb");//转换后文件的存放位置
        const int PCM_SIZE = 8192;
        const int MP3_SIZE = 8192;
        short int pcm_buffer[PCM_SIZE*2];
        unsigned char mp3_buffer[MP3_SIZE];
        lame_t lame = lame_init();
        lame_set_num_channels (lame, 2 ); // 设置 1 为单通道，默认为 2 双通道
        lame_set_in_samplerate(lame, 44100);//
        lame_set_brate (lame, 8);
        lame_set_mode (lame, 3);
        lame_set_VBR(lame, vbr_default);
        lame_set_quality (lame, 2); /* 2=high  5 = medium  7=low 音 质 */
        lame_init_params(lame);
        do {
            read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
            if (read == 0)
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            else
                write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
            
            fwrite(mp3_buffer, write, 1, mp3);
            
        } while (read != 0);
        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    }
    @catch (NSException *exception) {
         NSLog(@"%@",[exception description]);
    }
    @finally {
        completed(outPath);
    }
}
@end
